Skip to content

Conversation

davidkpiano
Copy link
Member

@davidkpiano davidkpiano commented Oct 13, 2025

Add skipEvent option to undoRedo() to exclude certain events from undo/redo history.

const store = createStore(
  undoRedo(
    {
      context: { count: 0 },
      on: {
        inc: (ctx) => ({ count: ctx.count + 1 }),
        log: (ctx) => ctx // No state change
      }
    },
    {
      skipEvent: (event, snapshot) => event.type === 'log'
    }
  )
);

Add snapshot parameter to getTransactionId function.

const store = createStore(
  undo(
    {
      // ...
    },
    {
      getTransactionId: (event, snapshot) =>
        snapshot.context.currentTransactionId
    }
  )
);

@changeset-bot
Copy link

changeset-bot bot commented Oct 13, 2025

🦋 Changeset detected

Latest commit: be2f559

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@xstate/store Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@davidkpiano davidkpiano requested a review from Andarist October 13, 2025 22:54
davidkpiano and others added 4 commits October 14, 2025 11:02
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
@farskid
Copy link
Collaborator

farskid commented Oct 14, 2025

@davidkpiano maybe skipEvents can access context too?

@davidkpiano
Copy link
Member Author

@davidkpiano maybe skipEvents can access context too?

I've thought of this too but what use-case are you thinking?

@farskid
Copy link
Collaborator

farskid commented Oct 14, 2025

@davidkpiano maybe skipEvents can access context too?

I've thought of this too but what use-case are you thinking?

Depends on the undo/redo API and how transaction ids are passed. Do you have an example of that?

@davidkpiano
Copy link
Member Author

davidkpiano commented Oct 14, 2025

Depends on the undo/redo API and how transaction ids are passed. Do you have an example of that?

const store = createStore(
  undoRedo(
    {
      context: { count: 0 },
      on: {
        inc: (ctx, ev: { t?: string }) => ({ count: ctx.count + 1 }),
        dec: (ctx) => ({ count: ctx.count - 1 })
      }
    },
    {
      getTransactionId: (event) => {
        return event.t;
      }
    }
  )
);

store.trigger.inc(); // not part of a transaction

store.trigger.inc({ t: 'a' }); // part of 'a' transaction
store.trigger.inc({ t: 'a' }); // part of 'a' transaction
store.trigger.inc({ t: 'a' }); // part of 'a' transaction

store.trigger.inc({ t: 'b' }); // part of 'b' transaction
store.trigger.inc({ t: 'b' }); // part of 'b' transaction
store.trigger.inc({ t: 'b' }); // part of 'b' transaction

store.trigger.undo(); // undoes three events from 'b' transaction

store.trigger.undo(); // undoes three events from 'a' transaction

store.trigger.undo(); // undoes a single event

@davidkpiano
Copy link
Member Author

@Andarist @farskid Ping

@farskid farskid self-requested a review October 16, 2025 20:27
Comment on lines +108 to +120
getTransactionId?: (
event: ExtractEvents<TEventPayloadMap>,
snapshot: StoreSnapshot<TContext>
) => string | null | undefined;
/**
* A function that returns whether an event should be skipped during
* undo/redo. Skipped events are not stored in history and are not replayed
* during undo/redo.
*/
skipEvent?: (
event: ExtractEvents<TEventPayloadMap>,
snapshot: StoreSnapshot<TContext>
) => boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: event actions API has order ctx, event whereas these two functions have the reverse order. They primarily work based on events which makes sense for event to be the first parameter but for consistency, we might want to consider unifying the order.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be a breaking change

@farskid farskid self-requested a review October 16, 2025 21:22
Copy link
Collaborator

@farskid farskid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM

@davidkpiano davidkpiano merged commit 6d00d3f into main Oct 17, 2025
1 check passed
@davidkpiano davidkpiano deleted the davidkpiano/store-skip branch October 17, 2025 14:26
@github-actions github-actions bot mentioned this pull request Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants